<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
	<title>代价较小的批量操作 | Elasticsearch: 权威指南 | Elastic</title>
    <!-- Give IE8 a fighting chance -->
    <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
    <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
	<link rel="stylesheet" type="text/css" href="../static/styles.css" />
</head>
<body>
<div class="main-container">
    <section id="content">
        
        <div class="content-wrapper">
            <section id="guide" lang="zh_cn">
                <div class="container">
                    <div class="row">
                        <div class="col-xs-12 col-sm-8 col-md-8 guide-section">
                            <div style="color:gray; word-break: break-all; font-size:12px;">原文地址: <a href="https://www.elastic.co/guide/cn/elasticsearch/guide/current/bulk.html" rel="nofollow">https://www.elastic.co/guide/cn/elasticsearch/guide/current/bulk.html</a>, 版权归 www.elastic.co 所有<br/>
                            英文版地址: <a href="https://www.elastic.co/guide/en/elasticsearch/guide/current/bulk.html" rel="nofollow">https://www.elastic.co/guide/en/elasticsearch/guide/current/bulk.html</a>
                            </div>
                        <!-- start body -->
                  <div class="page_header">
<b>请注意:</b><br>本书基于 Elasticsearch 2.x 版本，有些内容可能已经过时。
</div>
<div id="content">
<div class="breadcrumbs">
<span class="breadcrumb-link"><a href="index.html">Elasticsearch: 权威指南</a></span>
»
<span class="breadcrumb-link"><a href="getting-started.html">基础入门</a></span>
»
<span class="breadcrumb-link"><a href="data-in-data-out.html">数据输入和输出</a></span>
»
<span class="breadcrumb-node">代价较小的批量操作</span>
</div>
<div class="navheader">
<span class="prev">
<a href="_Retrieving_Multiple_Documents.html">« 取回多个文档</a>
</span>
<span class="next">
<a href="distributed-docs.html">分布式文档存储 »</a>
</span>
</div>
<div class="section">
<div class="titlepage"><div><div>
<h2 class="title">
<a id="bulk"></a>代价较小的批量操作<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elasticsearch-cn/elasticsearch-definitive-guide/edit/cn/030_Data/55_Bulk.asciidoc">edit</a>
</h2>
</div></div></div>
<p>与 <code class="literal">mget</code> 可以使我们一次取回多个文档同样的方式，
<code class="literal">bulk</code> API 允许在单个步骤中进行多次 <code class="literal">create</code> 、 <code class="literal">index</code> 、 <code class="literal">update</code> 或 <code class="literal">delete</code> 请求。
如果你需要索引一个数据流比如日志事件，它可以排队和索引数百或数千批次。</p>
<p><code class="literal">bulk</code> 与其他的请求体格式稍有不同，如下所示：</p>
<div class="pre_wrapper lang-js">
<pre class="programlisting prettyprint lang-js">{ action: { metadata }}\n
{ request body        }\n
{ action: { metadata }}\n
{ request body        }\n
...</pre>
</div>
<p>这种格式类似一个有效的单行 JSON 文档 <em>流</em> ，它通过换行符(<code class="literal">\n</code>)连接到一起。注意两个要点：</p>
<div class="ulist itemizedlist">
<ul class="itemizedlist">
<li class="listitem">
每行一定要以换行符(<code class="literal">\n</code>)结尾， <em>包括最后一行</em> 。这些换行符被用作一个标记，可以有效分隔行。
</li>
<li class="listitem">
这些行不能包含未转义的换行符，因为他们将会对解析造成干扰。这意味着这个 JSON <em>不</em> 能使用 pretty 参数打印。
</li>
</ul>
</div>
<div class="tip admon">
<div class="icon"></div>
<div class="admon_content">
<p>在 <a class="xref" href="distrib-multi-doc.html#bulk-format" title="为什么是有趣的格式？">为什么是有趣的格式？</a> 中， 我们解释为什么 <code class="literal">bulk</code> API 使用这种格式。</p>
</div>
</div>
<p><code class="literal">action/metadata</code> 行指定 <em>哪一个文档</em> 做 <em>什么操作</em> 。</p>
<p><code class="literal">action</code> 必须是以下选项之一:</p>
<div class="variablelist">
<dl class="variablelist">
<dt>
<span class="term">
<code class="literal">create</code>
</span>
</dt>
<dd>
如果文档不存在，那么就创建它。详情请见 <a class="xref" href="create-doc.html" title="创建新文档">创建新文档</a>。
</dd>
<dt>
<span class="term">
<code class="literal">index</code>
</span>
</dt>
<dd>
创建一个新文档或者替换一个现有的文档。详情请见 <a class="xref" href="index-doc.html" title="索引文档">索引文档</a> 和 <a class="xref" href="update-doc.html" title="更新整个文档">更新整个文档</a>。
</dd>
<dt>
<span class="term">
<code class="literal">update</code>
</span>
</dt>
<dd>
部分更新一个文档。详情请见 <a class="xref" href="partial-updates.html" title="文档的部分更新">文档的部分更新</a>。
</dd>
<dt>
<span class="term">
<code class="literal">delete</code>
</span>
</dt>
<dd>
删除一个文档。详情请见 <a class="xref" href="delete-doc.html" title="删除文档">删除文档</a>。
</dd>
</dl>
</div>
<p><code class="literal">metadata</code> 应该指定被索引、创建、更新或者删除的文档的 <code class="literal">_index</code> 、 <code class="literal">_type</code> 和 <code class="literal">_id</code> 。</p>
<p>例如，一个 <code class="literal">delete</code> 请求看起来是这样的：</p>
<div class="pre_wrapper lang-js">
<pre class="programlisting prettyprint lang-js">{ "delete": { "_index": "website", "_type": "blog", "_id": "123" }}</pre>
</div>
<p><code class="literal">request body</code> 行由文档的 <code class="literal">_source</code> 本身组成—​文档包含的字段和值。它是 <code class="literal">index</code> 和 <code class="literal">create</code> 操作所必需的，这是有道理的：你必须提供文档以索引。</p>
<p>它也是 <code class="literal">update</code> 操作所必需的，并且应该包含你传递给 <code class="literal">update</code> API 的相同请求体： <code class="literal">doc</code> 、 <code class="literal">upsert</code> 、 <code class="literal">script</code> 等等。
删除操作不需要 <code class="literal">request body</code> 行。</p>
<div class="pre_wrapper lang-js">
<pre class="programlisting prettyprint lang-js">{ "create":  { "_index": "website", "_type": "blog", "_id": "123" }}
{ "title":    "My first blog post" }</pre>
</div>
<p>如果不指定 <code class="literal">_id</code> ，将会自动生成一个 ID ：</p>
<div class="pre_wrapper lang-js">
<pre class="programlisting prettyprint lang-js">{ "index": { "_index": "website", "_type": "blog" }}
{ "title":    "My second blog post" }</pre>
</div>
<p>为了把所有的操作组合在一起，一个完整的 <code class="literal">bulk</code> 请求 有以下形式:</p>
<div class="pre_wrapper lang-sense">
<pre class="programlisting prettyprint lang-sense">POST /_bulk
{ "delete": { "_index": "website", "_type": "blog", "_id": "123" }} <a id="CO16-1"></a><i class="conum" data-value="1"></i>
{ "create": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "title":    "My first blog post" }
{ "index":  { "_index": "website", "_type": "blog" }}
{ "title":    "My second blog post" }
{ "update": { "_index": "website", "_type": "blog", "_id": "123", "_retry_on_conflict" : 3} }
{ "doc" : {"title" : "My updated blog post"} } <a id="CO16-2"></a><i class="conum" data-value="2"></i></pre>
</div>
<div class="sense_widget" data-snippet="snippets/030_Data/55_Bulk.json"></div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO16-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>请注意 <code class="literal">delete</code> 动作不能有请求体,它后面跟着的是另外一个操作。</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO16-2"><i class="conum" data-value="2"></i></a></p>
</td>
<td align="left" valign="top">
<p>谨记最后一个换行符不要落下。</p>
</td>
</tr>
</table>
</div>
<p>这个 Elasticsearch 响应包含 <code class="literal">items</code> 数组，这个数组的内容是以请求的顺序列出来的每个请求的结果。</p>
<div class="pre_wrapper lang-sense">
<pre class="programlisting prettyprint lang-sense">{
   "took": 4,
   "errors": false, <a id="CO17-1"></a><i class="conum" data-value="1"></i>
   "items": [
      {  "delete": {
            "_index":   "website",
            "_type":    "blog",
            "_id":      "123",
            "_version": 2,
            "status":   200,
            "found":    true
      }},
      {  "create": {
            "_index":   "website",
            "_type":    "blog",
            "_id":      "123",
            "_version": 3,
            "status":   201
      }},
      {  "create": {
            "_index":   "website",
            "_type":    "blog",
            "_id":      "EiwfApScQiiy7TIKFxRCTw",
            "_version": 1,
            "status":   201
      }},
      {  "update": {
            "_index":   "website",
            "_type":    "blog",
            "_id":      "123",
            "_version": 4,
            "status":   200
      }}
   ]
}</pre>
</div>
<div class="sense_widget" data-snippet="snippets/030_Data/55_Bulk.json"></div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO17-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>所有的子请求都成功完成。</p>
</td>
</tr>
</table>
</div>
<p>每个子请求都是独立执行，因此某个子请求的失败不会对其他子请求的成功与否造成影响。
如果其中任何子请求失败，最顶层的 <code class="literal">error</code> 标志被设置为 <code class="literal">true</code> ，并且在相应的请求报告出错误明细：</p>
<div class="pre_wrapper lang-sense">
<pre class="programlisting prettyprint lang-sense">POST /_bulk
{ "create": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "title":    "Cannot create - it already exists" }
{ "index":  { "_index": "website", "_type": "blog", "_id": "123" }}
{ "title":    "But we can update it" }</pre>
</div>
<div class="sense_widget" data-snippet="snippets/030_Data/55_Bulk_independent.json"></div>
<p>在响应中，我们看到 <code class="literal">create</code> 文档  <code class="literal">123</code> 失败，因为它已经存在。但是随后的 <code class="literal">index</code> 请求，也是对文档 <code class="literal">123</code> 操作，就成功了：</p>
<div class="pre_wrapper lang-sense">
<pre class="programlisting prettyprint lang-sense">{
   "took": 3,
   "errors": true, <a id="CO18-1"></a><i class="conum" data-value="1"></i>
   "items": [
      {  "create": {
            "_index":   "website",
            "_type":    "blog",
            "_id":      "123",
            "status":   409, <a id="CO18-2"></a><i class="conum" data-value="2"></i>
            "error":    "DocumentAlreadyExistsException <a id="CO18-3"></a><i class="conum" data-value="3"></i>
                        [[website][4] [blog][123]:
                        document already exists]"
      }},
      {  "index": {
            "_index":   "website",
            "_type":    "blog",
            "_id":      "123",
            "_version": 5,
            "status":   200 <a id="CO18-4"></a><i class="conum" data-value="4"></i>
      }}
   ]
}</pre>
</div>
<div class="sense_widget" data-snippet="snippets/030_Data/55_Bulk_independent.json"></div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO18-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>一个或者多个请求失败。</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO18-2"><i class="conum" data-value="2"></i></a></p>
</td>
<td align="left" valign="top">
<p>这个请求的HTTP状态码报告为 <code class="literal">409 CONFLICT</code> 。</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO18-3"><i class="conum" data-value="3"></i></a></p>
</td>
<td align="left" valign="top">
<p>解释为什么请求失败的错误信息。</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO18-4"><i class="conum" data-value="4"></i></a></p>
</td>
<td align="left" valign="top">
<p>第二个请求成功，返回 HTTP 状态码 <code class="literal">200 OK</code> 。</p>
</td>
</tr>
</table>
</div>
<p>这也意味着 <code class="literal">bulk</code> 请求不是原子的： 不能用它来实现事务控制。每个请求是单独处理的，因此一个请求的成功或失败不会影响其他的请求。</p>
<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="_Dont_Repeat_Yourself"></a>不要重复指定Index和Type<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elasticsearch-cn/elasticsearch-definitive-guide/edit/cn/030_Data/55_Bulk.asciidoc">edit</a>
</h3>
</div></div></div>
<p>也许你正在批量索引日志数据到相同的 <code class="literal">index</code> 和 <code class="literal">type</code> 中。
但为每一个文档指定相同的元数据是一种浪费。相反，可以像 <code class="literal">mget</code> API 一样，在 <code class="literal">bulk</code> 请求的 URL 中接收默认的 <code class="literal">/_index</code> 或者 <code class="literal">/_index/_type</code> ：</p>
<div class="pre_wrapper lang-sense">
<pre class="programlisting prettyprint lang-sense">POST /website/_bulk
{ "index": { "_type": "log" }}
{ "event": "User logged in" }</pre>
</div>
<div class="sense_widget" data-snippet="snippets/030_Data/55_Bulk_defaults.json"></div>
<p>你仍然可以覆盖元数据行中的 <code class="literal">_index</code> 和 <code class="literal">_type</code> , 但是它将使用 URL 中的这些元数据值作为默认值：</p>
<div class="pre_wrapper lang-sense">
<pre class="programlisting prettyprint lang-sense">POST /website/log/_bulk
{ "index": {}}
{ "event": "User logged in" }
{ "index": { "_type": "blog" }}
{ "title": "Overriding the default type" }</pre>
</div>
<div class="sense_widget" data-snippet="snippets/030_Data/55_Bulk_defaults.json"></div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="_How_Big_Is_Too_Big"></a>多大是太大了？<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elasticsearch-cn/elasticsearch-definitive-guide/edit/cn/030_Data/55_Bulk.asciidoc">edit</a>
</h3>
</div></div></div>
<p>整个批量请求都需要由接收到请求的节点加载到内存中，因此该请求越大，其他请求所能获得的内存就越少。
 批量请求的大小有一个最佳值，大于这个值，性能将不再提升，甚至会下降。
但是最佳值不是一个固定的值。它完全取决于硬件、文档的大小和复杂度、索引和搜索的负载的整体情况。</p>
<p>幸运的是，很容易找到这个 <em>最佳点</em> ：通过批量索引典型文档，并不断增加批量大小进行尝试。
当性能开始下降，那么你的批量大小就太大了。一个好的办法是开始时将 1,000 到 5,000 个文档作为一个批次, 如果你的文档非常大，那么就减少批量的文档个数。</p>
<p>密切关注你的批量请求的物理大小往往非常有用，一千个 1KB 的文档是完全不同于一千个 1MB 文档所占的物理大小。
一个好的批量大小在开始处理后所占用的物理大小约为 5-15 MB。</p>
</div>

</div>
<div class="navfooter">
<span class="prev">
<a href="_Retrieving_Multiple_Documents.html">« 取回多个文档</a>
</span>
<span class="next">
<a href="distributed-docs.html">分布式文档存储 »</a>
</span>
</div>
</div>

                  <!-- end body -->
                        </div>
                        <div class="col-xs-12 col-sm-4 col-md-4" id="right_col">
                        
                        </div>
                    </div>
                </div>
            </section>
        </div>
    </section>
</div>
<script src="../static/cn.js"></script>
</body>
</html>